---------------------------------------------------------------
File name   :  vv_ahblite_slave_bfm.e
Title       :  The slave BFM
Project     :  vv_ahblite UVC
Developers  :  stefan,filip
Created     :  29.07.2011.
Description :  This file adds slave functionality to the generic BFM.
Notes       :  
---------------------------------------------------------------
Copyright  (c)2011
---------------------------------------------------------------

<'

package vv_ahblite;

extend vv_ahblite_slave_bfm {
  
    -- This TCM is the main BFM loop that continually detects
    -- transactions received by this slave.
    main_loop()  @p_sys_smp.clk is {
    	var last_h_sel: bit = 0;
    	
        while TRUE {
            wait @p_bus_monitor.transaction_start;
                        
            --if p_slave.in_range(p_bus_monitor.transaction.addr) then { --@@@@
 
            if last_h_sel == 1 and p_slave.h_sel$ == 0 then {
            	-- Write transaction
	      		if last_transaction.write_op == 1 then{
	      			message(LOW, "SLAVE AGENT write instruction data{!}: ",last_transaction.addr ," ->> " ,p_smp.h_wdata$);
	      			
	      			if p_slave.use_mem == TRUE then {
	      				p_slave.write(last_transaction.addr,  p_smp.h_wdata$);
	      				--p_slave.write(response.addr, response.write_data);
	      			};
	      		};
	      		last_transaction = create_default_transaction();
	      		last_h_sel = 0;
            };
            
            
            -- activate slave if his hsel is active and hready is high
            if p_smp.h_ready$ == 1 and p_slave.h_sel$ == 1 then {
            	transaction_resp = p_driver.try_next_item();
                
                var default_resp : bool;
                if (transaction_resp == NULL) then {
                    default_resp = TRUE;
                    transaction_resp = create_default_transaction(); 
                };
                
                drive_transaction(transaction_resp);
                -- remmember last transaction and last hsel value
        		last_transaction = transaction_resp;
        		last_h_sel = p_slave.h_sel$;
        		
                if not default_resp {
                    -- Inform the sequence driver that the response is over.
                    emit p_driver.item_done;
                };
            };
        }; 
    }; 
    
    -- This TCM drive respons to a transaction from the DUT
    drive_transaction (response : SLAVE vv_ahblite_transaction)
      @p_sys_smp.clk is {
        message(HIGH, "transaction response started : ",response.transaction_str());
        response.start_transaction();
        
        -- Response control signals
        drive_transaction_control(response);                      
        
        -- Response data signals
        drive_transaction_data(response);   
        
        -- ******************************************************************  
        message(LOW, "transaction response completed : ",response.transaction_str());
        response.end_transaction();
    }; 
    
    -- This TCM drives the control signals of the transavtion response (HRESP and HREADY)
    drive_transaction_control (response : SLAVE vv_ahblite_transaction)
      @p_sys_smp.clk is {
      	
      	if(response.response == 1){
      		------ driving the 2-cycle error response
      		-- to start the error response, the slave drives hresp=1 and hready=0	
      		p_slave.h_resp$ = response.response;
      		p_slave.h_readyout$ = 0;
      		message(LOW, "SLAVE AGENT ERROR response started, FIRST cycle ");
      		wait cycle;
      		--in the next cycle of an error, the slave drives hready=1 to end the transfer
      		response.ready = 1;
      		message(LOW, "SLAVE AGENT ERROR response started, SECOND cycle ");
      		------ 
      	};
      	
        p_slave.h_resp$ = response.response; 
        p_slave.h_readyout$ = response.ready;        
        
    };
    
    -- This TCM drives the data of the transaction response
    drive_transaction_data (response : SLAVE vv_ahblite_transaction)
      @p_sys_smp.clk is { 	
      	-------------------------------WRITE-------------
      	--execute write operation using control signals from the last transaction
      	if (last_transaction.ready == 1 and last_transaction.response == 0 and (last_transaction.transfer not in [IDLE, BUSY])) {
      		-- Write transaction
      		if last_transaction.write_op == 1 then{
      			unpack(packing.low, p_smp.h_wdata$, response.write_data);  -- returns list of bytes
      			message(LOW, "SLAVE AGENT write instruction data: ",last_transaction.addr ," ->> " ,response.write_data);
      			
      			if p_slave.use_mem == TRUE then {
      				p_slave.write(last_transaction.addr, pack(packing.low, response.write_data));
      				--p_slave.write(response.addr, response.write_data);
      			};
      		};
      	};
      	----------------------------WAIT if there are wait states--------------
      	if response.ready == 0 {
      		message(LOW, "SLAVE AGENT WAIT states added: ", response.wait_states_num);
      		--------------------------new
      		--wait num_wait cycles
      		wait [response.wait_states_num]*cycle;
      		--drive ready 1
      		p_slave.h_readyout$ = 1;
            response.ready = 1;
      	};
      	------------------------------------------------------------------------
      	------------------------------READ----------------
      	if (response.ready == 1 and response.response == 0 and (response.transfer not in [IDLE, BUSY])) {
         -- if the slave drives ready=1 and response=0 then execute read or write transaction
         -- slaves must ignore IDLE and BUSY transfers
      		 
	         if response.write_op == 0 then{
	            -- Read transaction
	            if p_slave.use_mem == TRUE then {
	            	unpack(packing.low, p_slave.read(response.addr),response.read_data);
	                --response.read_data = p_slave.read(response.addr);
	            };
	            
                
	         	-- send to port  	
	            p_slave.h_rdata$ = pack(packing.low, response.read_data);
	         	message(LOW, "SLAVE AGENT read instruction data: ",response.addr," ->> " ,response.read_data);
	         	
	         };
      	};  
        -- ******************************************************************
    };
    
    -- This method creates a default transaction response
    create_default_transaction() : SLAVE vv_ahblite_transaction is {
        var default_item := new SLAVE vv_ahblite_transaction 
          (t) with {
            t.ready = 0;
            t.response = 0;
            t.wait_states_num = 0;
        };
        result = default_item;
    };
    
    -- This method initializes the slave values.
    init_values() is {
      	
        -- Init the signals
        p_slave.h_readyout$ = 1; --TODO
        p_slave.h_resp$ = 0;
        p_slave.h_rdata$ = 0;
        -- Init the items
        transaction_resp = NULL;
        --@@@@ at the begining SLAVE is not ready..
        last_transaction = create_default_transaction();
    }; 

    -- Run the main slave BFM continually.
    run() is also {
        message(LOW, "The slave BFM started");
        init_values();
        start main_loop();
    };      
};

'>
  
